#ifndef LISTA_H
#define LISTA_H
#include <string>
#include <iostream>
#include "nodo.h"
using namespace std;
 

class ErrorPosicion {};
class ErrorListaVacia {};
class ErrorNoMem {};
class ErrorIncorrecto{};

template <class Typo>
class Lista {

      Nodo<Typo> *primero,*ultimo;
      int numNodos;      
  
public:
    /// Construye una lista vacia
    Lista();
    
    /// Destruye la lista y todos sus elementos
    ~Lista();
    
    /// Devuelve el dato situado en la posicion pos de la lista
    Typo * lee(unsigned int pos);
    Typo & rlee(unsigned int pos);    
    
    /// Modifica el dato situado en la posicion pos estableciendo el nuevo valor
    void modifica(unsigned pos, Typo valor);
    
    /// Inserta  el dato en la posicion  indicada
    void inserta(Typo &t,unsigned pos);
    
    /// Elimina el dato situado en la posicion indicada de la lista
    Typo elimina(unsigned pos);
    
    ///  Inserta el dato t al final de la lista
    void aumenta(Typo &t);
    
    /// Tama Devuelve el numeor de elmentos de la lista
    unsigned tama();
    
    /// Elimina todos los elementos de la lista
    void limpia();
    
    /// Busca en la lista si se encuentra el elemento
    int busca(Typo &t);

/// Funciones Opcionales-------------------------------
// Consturctor copia Lista(Lista &copia){copia.titulo=titulo;}
/// Muestra

/*
Lista &operator= (Lista &c){titulo=c.titulo;}
bool operator== (Lista &c){if (titulo==c.titulo&&interprete==c.interprete) return 1;}

*/
};
/******************************************************************************/  
template <class Typo> Lista<Typo>::Lista(){ 
 //  cout <<"\n ----------------------------------------"<<endl;
 //        cout << "Lista::Lista()" << endl;
       //  primero=(Nodo<Typo> *)new Nodo<Typo> *;
      //   ultimo=(Nodo<Typo> *)new Nodo<Typo>*;         

         primero=NULL;
         ultimo=NULL;
         numNodos=0;
  
}
/******************************************************************************/  
template <class Typo> Lista<Typo>::~Lista(){
//         cout<<" \t --> Lista<Typo>::~Lista()"<<endl;

/* unsigned i;
 Typo *dato;
 dato= (Typo *) new Typo *;

 Typo *datoSig;
 datoSig= (Typo *) new Typo *; 

          for (i=0;i<tama();i++){
              dato=lee(i);
              datoSig=lee(i+1);
              dato->elimina(i);
              primero=datoSig;
          }*/
}
/******************************************************************************/  
template <class Typo> Typo *  Lista<Typo>::lee(unsigned int pos){
  // cout <<"\n ----------------------------------------"<<endl;
   //      cout << "Lista::lee()" << endl;         
         Typo *dato;
        // dato= (Typo *) new Typo *;
         Nodo<Typo> *aux;
        
             if (pos>numNodos){
                throw ErrorPosicion();
                }
               
         aux=primero; 
         
         if (pos==numNodos)
            aux=(*ultimo).anterior();
            
         else {                
                 for (int i=0;i<pos;i++){
                     aux=(*aux).siguiente();                     
                 }
         }
         
         dato=(*aux).leerDato();    
           
                  
         return dato;
}
/******************************************************************************/  
template <class Typo> Typo &  Lista<Typo>::rlee(unsigned int pos){
  // cout <<"\n ------------------------------------S----"<<endl;
   //      cout << "Lista::lee()" << endl;         

        // dato= (Typo *) new Typo *;
         Nodo<Typo> *aux;
        
             if (pos>numNodos){
                throw ErrorPosicion();
                }
               
         aux=primero; 
         
         if (pos==numNodos)
            aux=(*ultimo).anterior();
            
         else {                
                 for (int i=0;i<pos;i++){
                     aux=(*aux).siguiente();                     
                 }
         }
         
         Typo &dato=(*aux).rleerDato();    
           
                  
         return dato;
}
/******************************************************************************/  
template <class Typo> void Lista<Typo>::inserta(Typo &t,unsigned pos){
//   cout <<"----------------------------------------"<<endl;
  // cout << "Lista::inserta()" << endl;

  // Nodo<Typo> nodoNuevo(t);
   Nodo<Typo> *nodoNuevo;
   nodoNuevo = new Nodo<Typo>;

   Nodo<Typo> *aux,*aux2;

            
             
         (*nodoNuevo).escribirDato(t);
         (*nodoNuevo).siguiente(NULL);
         (*nodoNuevo).anterior(NULL);         

         if (pos>numNodos){
            throw ErrorPosicion();
            }
                 
//         cout<<"-nodNuevo = "<<(*nodoNuevo).leerDato()<<endl;
         if (numNodos==0){
//            cout<<"inserta en la lista vacia->"<<t<<endl;
            primero=ultimo=nodoNuevo;
            ++numNodos;         
         }
              
         else{
              if (pos==numNodos){
              // cout<<"inserta al final lista -> "<<t<<endl;
                  (*nodoNuevo).siguiente(primero);
                  (*nodoNuevo).anterior(ultimo);                  
                  (*ultimo).siguiente(nodoNuevo);
                  ultimo=nodoNuevo;
//                  (*ultimo).siguiente(*nodoNuevoo);
                  ++numNodos;                         
              }

             else { 
//                  cout<<"inserta en POSICCION ="<<pos<<"dato= "<<t<<endl;    
             
                        aux=primero;         
    
                         for (int i=0;i<pos-1;i++){
                             aux=(*aux).siguiente();                                          
                         }
                  
                    

                   aux2=(*aux).siguiente();                     
                  (*nodoNuevo).siguiente((*aux).siguiente());
                  (*nodoNuevo).anterior(aux);              
                  (*aux).siguiente(nodoNuevo);
                  (*aux2).anterior(nodoNuevo);  
                  ++numNodos;    
             }
         }
                    
}              
/******************************************************************************/  
template <class Typo> unsigned Lista<Typo>::tama(){ return numNodos;}  
/******************************************************************************/  
template <class Typo> void Lista<Typo>::aumenta(Typo &t){
         inserta(t,numNodos);
}   
/******************************************************************************/  
template <class Typo> void Lista<Typo>::modifica(unsigned pos, Typo valor){
//   cout <<"\n ----------------------------------------"<<endl;
//         cout << "Lista::modifiica(unsigned,Typo)" << endl;
         Nodo<Typo> *aux;
    
             if (pos>numNodos || numNodos==0){
                throw ErrorPosicion();
                }
                
         else{
              if (pos==numNodos){
                 (*ultimo).escribirDato(valor);
              }

             else { 
                  //cout<<"Modificar en POSICCION  lista "<<endl;    
                    aux=primero;         

                     for (int i=0;i<pos;i++){
                         aux=(*aux).siguiente();                                          
                     }
                 (*aux).escribirDato(valor);
             }
         }         
     
}                  
/******************************************************************************/  
template <class Typo> Typo Lista<Typo>::elimina(unsigned pos){
//   cout <<"\n ----------------------------------------"<<endl;
//         cout << "Lista::elimina(unsigned)" << endl;
         Typo datoViejo;
//         dato=new Typo *;
         Nodo<Typo> *aux,*aux2,*aux3;
      
        
         if (pos>numNodos || numNodos==0){
            throw ErrorPosicion();
            }
              
             
         else{
              if (pos==numNodos){
                   aux=ultimo;              
                  (*primero).anterior((*ultimo).anterior());     
                  (*(*ultimo).anterior()).siguiente(primero);                                              
                  ultimo=(*primero).anterior();
                  datoViejo=(*aux).leerDato();
                  delete aux;
                  --numNodos;                         
              }
              else if(pos==0)
              {
                   aux=primero;
                   (*(*primero).siguiente()).anterior(ultimo);
                   (*ultimo).siguiente((*primero).siguiente());
                   primero=(*primero).siguiente();
                   delete aux;
                   --numNodos;
              }
             else { 
                  //cout<<"borra en POSICCION  lista "<<pos<<endl;    
                    aux=primero;         

                     for (int i=0;i<pos;i++){
                         aux=(*aux).siguiente();                                          
                     }
                   //  cout<<"borrar -> "<<(*aux).leerDato()<<endl;
                     datoViejo=(*primero).leerDato();
                     aux2=(*aux).siguiente();

                                          
                     (*aux2).anterior((*aux).anterior());
                     aux3=(*aux).anterior();
                     (*aux3).siguiente(aux2);

                     delete aux;
                     
                  --numNodos;    
             }
         }         

    
         return datoViejo;         
}                  
/******************************************************************************/    
template <class Typo> void Lista<Typo>::limpia(){
//   cout <<"\n ----------------------------------------"<<endl;
   //      cout << "Lista::limpia()" << endl;
         int i=0;
         while (numNodos>=0)
         {
               (*primero).elimina(i);
               ++i;
               --numNodos;
         }
         primero=NULL;
         ultimo=NULL;   
     
}                  
/******************************************************************************/  
template <class Typo> int Lista<Typo>::busca(Typo &t){
//         cout << " \t --> Lista::buscar()" << endl;
         int i,encontrado=0;
         Nodo<Typo> *aux;        
         aux=primero; 
          Typo *dato ;
          dato=(Typo * )new Typo * ;          
          
         for (i=0;i<numNodos && encontrado==0;i++){
//             dato.verUsuario();system("pause");
             dato = (*aux).leerDato();
             if(t==*dato){
                encontrado=1;
                cout<<" econtrado"<<endl;
             }
             aux=(*aux).siguiente();                
         }
         return i;
}
#endif
